#include "stepMotor.h"

static int32_t _g_index = 0; // 励磁索引

/**
 * @name 顺时针单相激励
 * @description
 * @function
 * @returns {void}
 * @requires []
 */
static void _stepMotor_CW_phaseExcitation_A(void) {
    const static uint32_t phaseExcitation[] = {STEPMOTOR_PHASE_EXCITATION_A};
    // 相位激励
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PA, phaseExcitation[_g_index] & STEPMOTOR_PA ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PB, phaseExcitation[_g_index] & STEPMOTOR_PB ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PC, phaseExcitation[_g_index] & STEPMOTOR_PC ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PD, phaseExcitation[_g_index] & STEPMOTOR_PD ? Bit_SET : Bit_RESET);
    // 递增索引
    if (++_g_index >= sizeof(phaseExcitation) / sizeof(uint32_t))
        _g_index = 0;
}

/**
 * @name 逆时针单相激励
 * @description
 * @function
 * @returns {void}
 * @requires []
 */
static void _stepMotor_CWW_phaseExcitation_A(void) {
    const static uint32_t phaseExcitation[] = {STEPMOTOR_PHASE_EXCITATION_A};
    // 相位激励
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PA, phaseExcitation[_g_index] & STEPMOTOR_PA ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PB, phaseExcitation[_g_index] & STEPMOTOR_PB ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PC, phaseExcitation[_g_index] & STEPMOTOR_PC ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PD, phaseExcitation[_g_index] & STEPMOTOR_PD ? Bit_SET : Bit_RESET);
    // 递增索引
    if (--_g_index < 0)
        _g_index = sizeof(phaseExcitation) / sizeof(uint32_t) - 1;
}

/**
 * @name 顺时针双相激励
 * @description
 * @function
 * @returns {void}
 * @requires []
 */
static void _stepMotor_CW_phaseExcitation_B(void) {
    const static uint32_t phaseExcitation[] = {STEPMOTOR_PHASE_EXCITATION_B};
    // 相位激励
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PA, phaseExcitation[_g_index] & STEPMOTOR_PA ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PB, phaseExcitation[_g_index] & STEPMOTOR_PB ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PC, phaseExcitation[_g_index] & STEPMOTOR_PC ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PD, phaseExcitation[_g_index] & STEPMOTOR_PD ? Bit_SET : Bit_RESET);
    // 递增索引
    if (++_g_index >= sizeof(phaseExcitation) / sizeof(uint32_t))
        _g_index = 0;
}

/**
 * @name 逆时针双相激励
 * @description
 * @function
 * @returns {void}
 * @requires []
 */
static void _stepMotor_CWW_phaseExcitation_B(void) {
    const static uint32_t phaseExcitation[] = {STEPMOTOR_PHASE_EXCITATION_B};
    // 相位激励
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PA, phaseExcitation[_g_index] & STEPMOTOR_PA ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PB, phaseExcitation[_g_index] & STEPMOTOR_PB ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PC, phaseExcitation[_g_index] & STEPMOTOR_PC ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PD, phaseExcitation[_g_index] & STEPMOTOR_PD ? Bit_SET : Bit_RESET);
    // 递增索引
    if (--_g_index < 0)
        _g_index = sizeof(phaseExcitation) / sizeof(uint32_t) - 1;
}

/**
 * @name 顺时针单双激励
 * @description
 * @function
 * @returns {void}
 * @requires []
 */
static void _stepMotor_CW_phaseExcitation_AB(void) {
    const static uint32_t phaseExcitation[] = {STEPMOTOR_PHASE_EXCITATION_AB};
    // 相位激励
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PA, phaseExcitation[_g_index] & STEPMOTOR_PA ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PB, phaseExcitation[_g_index] & STEPMOTOR_PB ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PC, phaseExcitation[_g_index] & STEPMOTOR_PC ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PD, phaseExcitation[_g_index] & STEPMOTOR_PD ? Bit_SET : Bit_RESET);
    // 递增索引
    if (++_g_index >= sizeof(phaseExcitation) / sizeof(uint32_t))
        _g_index = 0;
}

/**
 * @name 逆时针单双激励
 * @description
 * @function
 * @returns {void}
 * @requires []
 */
static void _stepMotor_CWW_phaseExcitation_AB(void) {
    const static uint32_t phaseExcitation[] = {STEPMOTOR_PHASE_EXCITATION_AB};
    // 相位激励
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PA, phaseExcitation[_g_index] & STEPMOTOR_PA ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PB, phaseExcitation[_g_index] & STEPMOTOR_PB ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PC, phaseExcitation[_g_index] & STEPMOTOR_PC ? Bit_SET : Bit_RESET);
    GPIO_WriteBit(STEPMOTOR_GPIO, STEPMOTOR_PD, phaseExcitation[_g_index] & STEPMOTOR_PD ? Bit_SET : Bit_RESET);
    // 递增索引
    if (--_g_index < 0)
        _g_index = sizeof(phaseExcitation) / sizeof(uint32_t) - 1;
}

/**
 * @name 电机初始化
 * @description
 * @function
 * @returns {void}
 * @requires []
 */
void stepMotor_init(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    // 使能时钟
    STEPMOTOR_RCC_AHBPeriphClockCmd;
    // 配置GPIO
    GPIO_InitStruct.GPIO_Pin = STEPMOTOR_GPIO_Pin;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN;
    // 初始GPIO
    GPIO_Init(STEPMOTOR_GPIO, &GPIO_InitStruct);
    // 默认停止
    GPIO_ResetBits(STEPMOTOR_GPIO, STEPMOTOR_GPIO_Pin);
}

/**
 * @name 电机控制
 * @description
 * @function
 * @param {STEPMOTOR_DIRECTION} direction 方向
 * @param {STEPMOTOR_PHASE_EXCITATION} phaseExcitation 相位激励
 * @returns {void (*function)(void)}
 * @requires [direction,phaseExcitation]
 */
void (*stepMotor_control(const STEPMOTOR_DIRECTION direction, const STEPMOTOR_PHASE_EXCITATION phaseExcitation))(void) {
    const static void (*cw_controls[])(void) = {_stepMotor_CW_phaseExcitation_A, _stepMotor_CW_phaseExcitation_B, _stepMotor_CW_phaseExcitation_AB};
    const static void (*ccw_controls[])(void) = {_stepMotor_CWW_phaseExcitation_A, _stepMotor_CWW_phaseExcitation_B, _stepMotor_CWW_phaseExcitation_AB};
    // 选中控制
    switch (direction) {
    case STEPMOTOR_DIRECTION_CW:
        return cw_controls[phaseExcitation];
    case STEPMOTOR_DIRECTION_CCW:
        return ccw_controls[phaseExcitation];
    default:
        return NULL;
    }
}
